<template>
  <div style="height: 82vh; display: flex; flex-direction: column;">
    <!-- 固定在顶部的搜索区域 -->
    <div style="position: sticky; top: 0; z-index: 10; background-color: white; padding: 10px 0; border-bottom: 1px solid #ebeef5;">
      <div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: center;">
        <el-select v-model="creatorSearch" filterable placeholder="选择创建人" style="width: 150px" @keyup.enter.native="load(1)">
          <el-option
              v-for="item in userOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value">
          </el-option>
        </el-select>
        <el-input style="width: 200px" placeholder="图号" v-model="tuhaoSearch" @keyup.enter.native="load(1)" native-type="search"></el-input>
        <el-input style="width: 200px" placeholder="名称" v-model="nameSearch" @keyup.enter.native="load(1)" native-type="search"></el-input>
        <el-input style="width: 200px" placeholder="系统编码" v-model="syscodeSearch" @keyup.enter.native="load(1)" native-type="search"></el-input>
        <el-input style="width: 200px" placeholder="人工编码" v-model="bianmaSearch" @keyup.enter.native="load(1)" native-type="search"></el-input>
        <!-- <el-button type="primary" @click="load(1)">查询</el-button> -->
        <el-button icon="el-icon-search" circle @click="load(1)" :loading="pageLoading"></el-button>
        <el-button type="warning" plain @click="reset" :loading="pageLoading">重置/刷新</el-button>
        <el-button type="primary" plain @click="handleAddOrEdit">新增信息</el-button>
        <el-button type="danger" plain @click="handleDelBatch" :loading="pageLoading">批量删除</el-button>
        <!-- <el-button type="info" plain @click="downloadExcelTemplate" style="margin-left: 10px">下载Excel清单筛选模板</el-button> -->
        <el-button type="warning" plain @click="showAutocodeDialog">单次编码</el-button>
        <el-button type="success" plain @click="showWsChatDialog">发站内信</el-button>
        <el-button type="info" plain @click="exportAllData" :loading="pageLoading">一键导出</el-button>
      </div>
      <!-- <div style="margin: 10px 0">
      </div> -->
    </div>
    
    <!-- 可滚动的表格区域 -->
    <div style="flex: 1; overflow-y: auto; padding-bottom: 30px;">
      <!-- 整个表格，有多选框 -->
      <el-table :height="'100%'"  v-loading="pageLoading" element-loading-text="拼命加载中" :data="tableData" stripe :header-cell-style="{backgroundColor: 'aliceblue',color: '#666'}"
      @selection-change="handleSelectionChange">
    <!--    复选框-->
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="id" label="ID" width="80"></el-table-column>
        <!--<el-table-column prop="xuhao" label="序号" width="100"></el-table-column>-->
        <el-table-column prop="tuhao" label="图号" width="180px"></el-table-column>
        <el-table-column prop="name" label="名称" width="180px"></el-table-column>
        <el-table-column prop="guige" label="规格" ></el-table-column>
        <el-table-column prop="cailiao" label="材料" ></el-table-column>
        <el-table-column prop="danzhong" label="单重" ></el-table-column>
         <el-table-column prop="leibie" label="类别" width="150">
          <template v-slot="scope">
            <el-tag :type="getStatusType(scope.row.leibie)">{{scope.row.leibie}}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="syscode" label="系统编码" width="140px"></el-table-column>
        <el-table-column prop="bianma" label="人工编码" width="140px"></el-table-column>
        <el-table-column prop="creatorName" label="创建人" width="80px"></el-table-column>
        <el-table-column prop="creatTime" label="创建时间" width="140px"></el-table-column>
        <!-- <el-table-column prop="modifierName" label="更新人" width="80px"></el-table-column>
        <el-table-column prop="updateTime" label="更新时间" width="140px"></el-table-column> -->
        <el-table-column prop="beizhu" label="备注"></el-table-column>
        <el-table-column fixed="right" label="操作" align="center" width="240px">
          <template v-slot="scope">
            <!-- <el-button size="mini" type="primary" plain @click="handlerEdit(scope.row)">编辑</el-button> -->
            <el-button size="mini" type="danger" plain @click="handleDel(scope.row)" :loading="pageLoading">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
    
    <!-- 固定在底部的分页区域 -->
    <div style="position: sticky; bottom: 0; background-color: white; padding: 5px 0; border-top: 1px solid #ebeef5; display: flex; justify-content: center; align-items: center; z-index: 10; margin-bottom: 0;">
      <div style="display: flex; align-items: center;">
        <div style="display: flex; align-items: center; margin-right: 20px;">
          <span style="margin-right: 10px;">每页显示:</span>
          <el-input-number v-model="customPageSize" :min="1" :max="100" :step="1" style="width: 120px; margin-right: 10px;"></el-input-number>
          <el-button type="primary" size="small" @click="updatePageSize" :loading="pageSizeLoading">确定</el-button>
        </div>
        <el-pagination @current-change="handleCurrentChange"
                      :current-page="pageNum"
                      :page-size="pageSize"
                      layout="total,prev,pager,next"
                      :total="total">
        </el-pagination>
      </div>
    </div>
    
    <!-- 新增表单需要弹窗包裹 -->
    <el-dialog :title="form.id ? '修改零件信息' : '新增零件信息'"
              :visible.sync="formVisible"
              width="40%"
              @close="closeFormVisible" >
      <el-form :model="form" label-width="80px" style="padding-right: 20px" :rules="rules" ref="formRef">
        <el-form-item label="图号" prop="tuhao">
          <el-input v-model="form.tuhao" placeholder="图号(必填)"></el-input>
        </el-form-item>

         <el-form-item label="名称" prop="name">
          <el-input v-model="form.name" placeholder="名称(必填)"></el-input>
        </el-form-item>

        <el-form-item label="规格" prop="guige">
          <el-input v-model="form.guige" placeholder="规格"></el-input>
        </el-form-item>

        <el-form-item label="材料" prop="cailiao">
          <el-input v-model="form.cailiao" placeholder="材料"></el-input>
        </el-form-item>

        <el-form-item label="类别" prop="leibie">
          <el-select v-model="form.leibie" placeholder="请选择类别">
            <el-option value="标准件" label="标准件"></el-option>
            <el-option value="机加件" label="机加件"></el-option>
            <el-option value="钣金件" label="钣金件"></el-option>
            <el-option value="组件" label="组件"></el-option>
            <el-option value="机加/钣金件" label="机加/钣金件"></el-option>
          </el-select>
        </el-form-item>

        <el-form-item label="人工编码" prop="bianma">
          <el-input v-model="form.bianma" placeholder="人工编码"></el-input>
        </el-form-item>

        <el-form-item v-if="form.id" label="系统编码" prop="syscode">
          <el-input v-model="form.syscode" placeholder="系统编码" :disabled="true"></el-input>
        </el-form-item>

      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="formVisible = false">取消</el-button>
        <el-button type="primary" @click="save" :loading="saveLoad">提交</el-button>
      </div>
    </el-dialog>

    <el-dialog :visible.sync="autocodeVisible" :close-on-click-modal="false" title="自动编码小程序-初始版(v0.0.1)">
      <Autocode />
    </el-dialog>

    <el-dialog :visible.sync="wsDialogVisible" title="发送站内信" width="80%" @close="closeFormVisible">
      <WsChat/>
    </el-dialog>
  </div>
</template>

<script>
  import Autocode from '@/views/manager/utils/Autocode.vue';
  import WsChat from '@/views/manager/utils/WsChat.vue';
  // import E from 'wangeditor'
  // import hljs from 'highlight.js'
  export default {
    name: "CodeLib",
    inject: { 
      getWebsocket: { 
        default: () => () => null 
      } 
    }, // 获取父组件提供的websocket获取函数
    data(){
      return {
        tableData: []//表数据
        ,pageNum: 1//当前页码
        ,pageSize: 15//每页数量
        ,customPageSize: 15//用户输入的每页数量
        ,tuhaoSearch: ''
        ,creatorSearch: ''
        ,wsOppo: ''
        ,nameSearch: ''
        ,bianmaSearch: ''
        ,syscodeSearch: ''
        ,total: 0 //数据总条数
        ,user: JSON.parse(localStorage.getItem('userInfo') || '{}')
        ,ids: []
        ,formVisible: false //默认不显示新增表单弹窗
        ,form: {
          autoCode: true, // 是否自动处理物料编码
          deWeight: true // 是否自动去除重复项
        } //弹窗表单
        ,originalOnMessage: null // 保存原始的onmessage处理函数
        ,rules: {
          //校验规则
          tuhao: [
            {
              required: true,
              message: '请输入图号',
              trigger: 'blur',
            }
          ],
          name: [
            {
              required: true,
              message: '请输入名称',
              trigger: 'blur',
            }
          ]
        },fileList: []
        ,selectVal: "", // select框的绑定值
        selectName: "", // select框显示的name
        // 树形控件数据
        treeData: [],
        defaultProps: {
          children: "children",
          label: "name",
        },
        // 标签数组
        tagList: [
          { value: "admin", label: "管理员" },
          { value: "user", label: "用户" },
          { value: "test", label: "测试员" },
        ]
        ,userOptions: []
        ,userOptionsLoading: false
        ,saveLoad: false
        ,pageLoading: false // 添加加载状态变量1
        ,pageSizeLoading: false // 添加每页大小调整的加载状态
        ,autocodeVisible: false // 添加自动编码弹窗的显示状态
        ,wsDialogVisible: false //站内信弹窗
        ,msgContent: '' //测试输入内容
        ,msgList: [] //消息列表：发送或接收记录
        ,wsLoading: false // 聊天记录加载状态
        ,editor: null //富文本编辑框
        // ,wsForm: { // 站内信表单数据
        //   wsOppo: '',
        //   content: ''
        // }
        // ,wsRules: { // 站内信表单规则
        //   wsOppo: [
        //     {
        //       required: true,
        //       message: '请选择会话人',
        //       trigger: 'change'
        //     }
        //   ],
        //   content: [
        //     {
        //       required: true,
        //       message: '消息内容不能为空',
        //       trigger: 'blur'
        //     }
        //   ],
        // },
        // ,showTime: {}// 使用对象存储每个消息的时间显示状态
        ,timers: {} // 使用对象存储每个消息的定时器
      }
    },
    created() {
      // 尝试从localStorage读取页面大小设置，如果存在则使用，不存在则使用默认值
      const savedPageSize = localStorage.getItem('codeLibPageSize');
      if (savedPageSize && !isNaN(savedPageSize)) {
        this.pageSize = parseInt(savedPageSize);
        this.customPageSize = parseInt(savedPageSize);
      }
      this.pageLoading = true;
      this.load();
    },
    //安装
    mounted() {
      this.initUsersOptions();
      this.initWebSocketListener();
    },
    //vue销毁之前
    beforeDestroy() {
      // 清理WebSocket事件监听器
      const websocket = this.getWebsocket();
      if (websocket && this.originalOnMessage) {
        websocket.onmessage = this.originalOnMessage;
      }
      // 清理所有定时器
      if (this.timers && typeof this.timers === 'object') {
        Object.values(this.timers).forEach(timer => {
          if (timer) clearTimeout(timer);
        });
      }
      this.timers = {};
    },
    computed: {

    },
    components: {
      Autocode,
      WsChat
    },
    watch: {
      
    },
    methods: {
      // 初始化WebSocket监听器
      initWebSocketListener() {
        const websocket = this.getWebsocket();
        if (websocket) {
          // 保存原始的onmessage处理函数
          this.originalOnMessage = websocket.onmessage;
          
          // 创建新的onmessage处理函数
          const newOnMessage = (event) => {
            try {
              const messageData = JSON.parse(event.data);
              // 检查消息类型是否为success
              if (messageData.type === 'success') {
                console.log('收到success类型消息:', messageData.content);
                // 调用重载方法刷新列表
                this.reset();
              }
            } catch (error) {
              console.error('解析WebSocket消息失败:', error);
            }
            
            // 调用原始的onmessage处理函数，确保不影响现有功能
            if (typeof this.originalOnMessage === 'function') {
              this.originalOnMessage(event);
            }
          };
          
          // 绑定this上下文
          websocket.onmessage = newOnMessage.bind(this);
        }
      },
      
      initUsersOptions() {
        this.userOptionsLoading = true;
        this.$request.get('/user/options').then(res => {
          if (res.code === '200') {
            this.userOptions = res.data;
          } else {
            this.$message.error('获取用户选项失败');
            this.userOptions = [];
          }
        }).catch(() => {
          this.$message.error('网络错误，获取用户选项失败');
          this.userOptions = [];
        }).finally(() => {
          this.userOptionsLoading = false;
        });
      },
      
      reset(){
        console.log('重置');
        this.pageLoading = true;
        this.tuhaoSearch = ''
        this.creatorSearch = ''
        this.nameSearch = ''
        this.bianmaSearch = ''
        this.syscodeSearch = ''
        this.load()
      },

      load(pageNum){ 
        console.log('重新加载'); 
        if (pageNum) this.pageNum = pageNum;  //分页查询时自动切换到第一页
        return new Promise((resolve, reject) => {
          this.$request.get('/codelib/findByPage',{
            params:{
              pageNum: this.pageNum,
              pageSize: this.pageSize,
              tuhao: this.tuhaoSearch,
              creator: this.creatorSearch,
              name: this.nameSearch,
              bianma: this.bianmaSearch,
              syscode: this.syscodeSearch
            }
          }).then(res => {
            if (res.code === "200"){
              if (res.data){
                if (res.data.records){
                  this.tableData = res.data.records
                }else {
                  this.tableData = res.data
                }
              }
              this.total = res.data.total
            }else {
              this.$message.error(res.msg)
            }
            this.pageLoading = false;
            resolve();
          }).catch(error => {
            this.pageLoading = false;
            reject(error);
          });
        });
      },
      //切换页码
      handleCurrentChange(pageNum){
        this.load(pageNum)
      },
      // 更新每页显示数量
      updatePageSize(){
        if (this.customPageSize && this.customPageSize > 0) {
          this.pageSizeLoading = true;
          this.pageSize = this.customPageSize;
          // 将页面大小设置保存到localStorage
          localStorage.setItem('codeLibPageSize', this.customPageSize.toString());
          this.pageNum = 1; // 重置为第一页
          this.load(1).finally(() => {
            this.pageSizeLoading = false;
          });
        } else {
          this.$message.warning('请输入有效的每页数量');
        }
      },
      
      // 新增辅助方法
      parseFileName(headers) {
        const defaultName = '未命名文件';
        const disposition = headers.get('Content-Disposition') || defaultName;
        try{
          const matches = disposition.match(/filename\*?=(?:UTF-8'')?([^;]+)/i);
          if (matches) return decodeURIComponent(matches[1]);
          // 处理常规文件名
          const filenameMatch = disposition.match(/filename="?([^"]+)"?/i);
          return filenameMatch ? filenameMatch[1] : defaultName;
        }catch (e) {
          console.error('文件名异常:', e);
          return defaultName;
        }
      },
      triggerFileDownload(blob, fileName) {
        try {
          const link = document.createElement('a');
          if (!blob.size) throw new Error('Empty file content');
          
          link.href = URL.createObjectURL(blob);
          link.download = fileName;
          document.body.appendChild(link);
          link.click();
          
          setTimeout(() => {
              URL.revokeObjectURL(link.href);
              link.remove();
          }, 100);
        } catch (error) {
            console.error('Download failed:', error);
            this.$message.error('文件下载失败：无效的文件内容');
        }
      },
      handleAddOrEdit(row){
        if (row.id){
          //编辑模式
          this.form = JSON.parse(JSON.stringify(row)) //弹窗带出来信息,浅拷贝是内存指向，深拷贝是开区域赋值
          // 确保 autoCode 有默认值
          if (this.form.autoCode === null) {
            this.form.autoCode = false;
          }
          if (this.form.deWeight === null) {
            this.form.deWeight = false;
          }
          //需要把upload组件的fileList带出来
          if (this.form.fileListJson){
            this.fileList = this.form.fileListJson
          }else {
            this.fileList = []
          }
          //接收人
          this.selectVal = this.form.recipient
          this.selectName = this.form.recipientName
        }else {
          this.form = {
            autoCode: true,
            deWeight: true
          } //新增数据时清空表单
          this.fileList = [] //清空上传组件
        }
        this.formVisible = true //打开弹窗
        //初始化选择框
        // this.initRecipientSelect();
      },
      //编辑
      handlerEdit(row){
        this.handleAddOrEdit(row);
        this.$nextTick(() => {
          // 确保表单验证状态被清除
          if (this.$refs.formRef) {
            this.$refs.formRef.clearValidate();
          }
        });
      },
      //单个删除
      handleDel(row){
        // 使用row.name替代row.workName，与后端实体字段保持一致
        const confirmText = row.name ? `确认要删除【${row.name}】这条记录吗？` : '确认要删除这条记录吗？';
        
        this.$confirm(confirmText, '确认删除', {type: "warning"})
          .then(() => {
            // 显示加载状态
            this.pageLoading = true;
            
            this.$request.delete(`/codelib/delete/${row.id}`)
              .then(res => {
                if (res.code === '200') {
                  this.$message.success(res.data || "删除成功");
                } else {
                  this.$message.error(`删除失败：${res.msg || '未知错误'}`);
                }
              })
              .catch(error => {
                console.error('删除请求异常:', error);
                this.$message.error('网络异常，请稍后重试');
              })
              .finally(() => {
                this.load(this.pageNum); //刷新表格
              });
          })
          .catch(() => {
            // 用户取消删除，可选提示
            // this.$message.info('已取消删除操作');
          });
      },
      //批量删除之前--多选框，参数是选中的行对象
      handleSelectionChange(rows){
        this.ids = rows.map(row => row.id) //流和表达式，将行id提取出来存入数组
      },
      //批量删除
      handleDelBatch(){
        //校验：点击批量删除按钮之前，未选择多选框时提示
        if (!this.ids || this.ids.length === 0){
          // 确认是否清空全部数据
          this.$confirm('确认要清空全部数据吗？此操作不可恢复！', '警告', {
            type: 'warning',
            confirmButtonText: '确定清空',
            cancelButtonText: '取消',
            distinguishCancelAndClose: true
          }).then(() => {
            // 显示加载状态
            this.pageLoading = true;
            this.$request.delete('/codelib/deleteAll')
              .then(res => {
                if (res.code === '200') {
                  this.$message.success(res.msg || '清空全部数据成功');
                } else {
                  this.$message.error(`清空失败: ${res.msg || '未知错误'}`);
                }
              })
              .catch(error => {
                console.error('清空全部数据请求异常:', error);
                this.$message.error('网络异常，请稍后重试');
              })
              .finally(() => {
                this.pageLoading = false;
                this.load(this.pageNum); // 刷新表格
              });
          }).catch(() => {
            // 用户取消清空
          });
        }else{
          const confirmText = `确认要删除选中的 ${this.ids.length} 条记录吗？`;
          this.$confirm(confirmText, '确认删除', {type: "warning"})
            .then(() => {
              // 显示加载状态
              this.pageLoading = true;
              this.$request.delete('/codelib/deleteBatch', {
                data: this.ids // Vue Axios中delete请求携带body数据需要用data字段
              })
              .then(res => {
                if (res.code === '200') {
                  this.$message.success("批量删除成功");
                  this.ids = []; // 清空选中状态
                } else {
                  this.$message.error(`批量删除失败: ${res.msg || '未知错误'}`);
                }
              })
              .catch(error => {
                console.error('批量删除请求异常:', error);
                this.$message.error('网络异常，请稍后重试');
              })
              .finally(() => {
                this.load(this.pageNum); //刷新表格
              });
            })
            .catch(() => {
              // 用户取消删除
            });
          }
      },
      //关闭弹窗后的回调方法
      closeFormVisible(){
        //清除rules提示信息
        if (this.$refs.formRef) {
          this.$refs.formRef.clearValidate()
        }
        // 销毁编辑器实例
        if (this.editor) {
          this.editor.destroy()
          this.editor = null
        }
      },
      //关闭ws弹窗后的回调方法
      closeWsDialogVisible(){
        //清除rules提示信息
        // this.$refs.formRef.clearValidate()
        //销毁富文本编辑器对象
        this.editor.destroy()
        this.editor = null
      },
      //上传文件组件，文件改变事件(添加文件ready，上传成功success/失败error，都会被调用，至少2次)
      handleChange(file, fileList){
        if (file.status !== 'ready') return; //文件未准备好是减少调用次数
      },
      //上传文件组件，文件预览
      handlePreview(file){
        const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'webp'];

        let fileExtensionMatch  = file.response.data.fileName.match(/\.([^\.]+)$/)
        let fileExtension = fileExtensionMatch ? fileExtensionMatch[1] : ''  //文件扩展名
        if (imageExtensions.includes(fileExtension.toLowerCase())) {
          this.$message.warning('预览图片功能正在开发中……')
        }else {
          this.$message.warning('选中的文件是非图片，暂不支持预览')
        }

      },
      //上传文件组件，限制附件个数
      handleExceed(files, fileList){
        this.$message.warning(`当前限制选择 30 个附件，本次选择了 ${files.length} 个文件，共选择了 ${files.length + fileList.length} 个文件`);
      },
      //上传文件组件，成功后记录文件名和文件路径
      handleOnSuccess(response, file, fileList){
        this.fileList = fileList;
        //改变附件名称
        this.form.attachName = this.fileList.map(file => file.name).join(',')
        if(this.form.attachName.length > 100){
          this.form.attachName = this.form.attachName.substring(0,97) + '...'
        }
      },
      //上传组件，移除元素之前
      beforeRemoved(file,fileList){
        if (file && file.status === 'success'){
          this.$confirm(`确定移除【${file.name}】吗？`).then(()=>{
            //刷新一下全局变量
            this.fileList = fileList
            // console.log(fileList)
            //确认移除,改变附件名称
            this.form.attachName = this.fileList.map(file => file.name).join(',')
            return true
          }).catch(() => {
            //取消或关闭
            return false
          })
        }
      },
      //上传文件之前
      beforeUpload(file){
        if (this.form.workName === undefined || this.form.workName === null){
          this.$message.error("请选择任务名称后再上传文件")
          return false
        }
        const workName = this.form.workName;
        const fileType = file.type;
        if (workName === '合并PDF' || workName === '拆分PDF'){
          const isPDF = fileType === 'application/pdf';
          if (!isPDF){
            this.$message.error('操作PDF任务时只能上传PDF文件！')
            return false
          }
        }

        let size = file.size;
        let maxSize = 100 * 1024 * 1024;
        if (size > maxSize){
          // this.$message.warning("附件大小不能超过100MB")
          // return false
          // this.$refs.uploader.abort() //终止上传
          return this.$confirm('当前附件【'+file.name+'】文件大小超出100MB安全范围，继续上传可能会出错，请确认是否继续上传？','警告提示')
        }
      },
      //保存/修改
      save() {
        //校验表单
        this.$refs.formRef.validate((valid) => {
          if (valid) {
            this.saveLoad = true;
            this.sendApi();
          } else {
            this.$message.warning('表单校验未通过')
            return false
          }
        })
      },
      //向接口发送
      sendApi(){
        this.$request({
          //有id就是编辑
          method: this.form.id ? 'PUT' : 'POST',
          data: this.form,
          url: this.form.id ? '/codelib/update' : '/codelib/save',
        }).then((res) => {
          if (res.code === '200') {
            //保存成功
            this.$message.success('保存成功')
            this.formVisible = false
            this.load(this.pageNum)
          } else {
            this.$message.error(res.msg) //错误信息
            return false
          }
          //无论是否保存成功，都要把fileList清空
          this.fileList = []
          this.saveLoad = false;
        }).finally(() => {
          this.saveLoad = false;
        });
      },
      getStatusType(leibie) {
        switch (leibie) {
          case '标准件':
            return 'info';
          case '组件':
            return 'warning';
          case '机加件':
            return 'success';
          case '钣金件':
            return 'danger';
          default:
            return 'info'; // 默认没有特殊样式
        }
      },
      // //清空聊天消息
      // cleanChatMsg(){
      //   // 检查是否选择了会话人
      //   if(!this.wsForm.wsOppo || this.wsForm.wsOppo === ''){
      //     this.$message.warning('请先选择会话人');
      //     return;
      //   }
      //   this.$confirm('确认要清空与该用户的聊天记录吗？', '确认清空', {
      //     type: 'warning'
      //   }).then(() => {
      //     this.$request.delete('/chat/cleanChatRecords', {
      //       params: {
      //         userId: this.user.id,
      //         oppoId: this.wsForm.wsOppo
      //       }
      //     }).then(res => {
      //       if(res.code === '200'){
      //         this.msgList = [];
      //         this.$message.success('聊天记录已清空');
      //       }else{
      //         this.$message.error('清空失败：' + res.msg);
      //       }
      //     }).catch(error => {
      //       this.$message.error('网络错误，清空失败');
      //       console.error('清空聊天记录失败:', error);
      //     });
      //   }).catch(() => {
      //     // 取消操作
      //   });
      // },
      // 滚动到底部方法
      scrollToBottom() {
        // 延迟执行，确保DOM已经更新
        setTimeout(() => {
          if (this.$refs.messageContainer) {
            this.$refs.messageContainer.scrollTop = this.$refs.messageContainer.scrollHeight;
          }
        }, 100);
      },
      sendInitMsg(){
        const websocket = this.getWebsocket();
        const msg = {
            type: 'init',
            content: this.user.id+'号用户正在连接……',
            uid: this.user.id,
            oppo: '0'
        };
        websocket.send(JSON.stringify(msg));
        // this.msgList.push({
        //   type: "me", 
        //   content: msg.content, 
        //   time: new Date().toLocaleString() 
        // });
      },
      // 站内信发送消息
      // sendChatMsg() {
      //   // 确保富文本编辑器有内容
      //   if (this.editor) {
      //     this.wsForm.content = this.editor.txt.html();
      //   }
      //   // 表单验证
      //   this.$refs.wsForm.validate((valid) => {
      //     if (valid) {
      //       const websocket = this.getWebsocket();
      //       if (!websocket) {
      //         this.$message.error('WebSocket未连接');
      //         return;
      //       }
      //       if (websocket.readyState !== WebSocket.OPEN) {
      //           this.$message.warning('WebSocket连接未准备好，当前状态：' + websocket.readyState);
      //           return;
      //       }
      //       // 处理特殊字符，避免数据库存储错误
      //       let processedContent = this.wsForm.content;
      //       try {
      //         // 可以在这里添加更多的处理逻辑
      //         processedContent = processedContent.replace(/[\xF0-\xF7][\x80-\xBF]{3}/g, ''); // 移除表情符号
      //         // this.$message.warning("表情符号比较特殊，对方可能收不到表情符号。")
      //       } catch (e) {
      //         console.error('处理内容时出错:', e);
      //       }
      //       const msg = {
      //           type: 'chat',
      //           content: processedContent,
      //           uid: this.user.id,
      //           oppo: this.wsForm.wsOppo
      //       };
      //       websocket.send(JSON.stringify(msg));
      //       this.msgList.push({
      //         type: "me", 
      //         content: msg.content, 
      //         time: new Date().toLocaleString() 
      //       });
      //       if (this.msgList.length > 100) this.msgList.shift(); //最多保留100条消息
      //       // 清空表单
      //       this.wsForm.content = '';
      //       if (this.editor) {
      //         this.editor.txt.clear();
      //       }
      //       this.scrollToBottom();
      //     }
      //   });
      // },
      //初始化用户选择框
      initUsersOptions(){
        this.$request({
          method: 'GET',
          url: '/user/getSelect',
        }).then((res) => {
          if (res.code === '200') {
            this.userOptions = res.data;
          } else {
            this.$message.error(res.msg) //错误信息
            return false
          }
        })
      },
      

      // 添加 handleDrop 方法
      handleDrop(event) {
        event.preventDefault();
        // 可以根据需求添加文件处理逻辑
        console.log('文件已拖拽放下', event.dataTransfer.files);
      },
      // 显示WS-Chat弹窗
      showWsChatDialog() {
        this.wsDialogVisible = true;
      },
      // 显示自动编码弹窗
      showAutocodeDialog() {
        this.autocodeVisible = true;
        this.$request.get('/bom/clearCount').then(res => {
          if (res.code === '200') {
            this.$message.success(res.data || '成功连接服务并清除缓存');
          } else {
            this.$message.error(res.message || '缓存清除失败');
          }
        })
        .catch(error => {
          this.$message.error('请求失败: ' + error.message);
        });
      },
      //导出全部数据
      exportAllData() {
        this.$confirm('确定要导出全部数据吗？这可能需要一些时间...', '确认导出', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'info'
        }).then(() => {
          this.pageLoading = true;
          // 调用API获取所有数据（不分页）
          this.$request.get('/codelib/findAll', {
            params: {
              tuhao: this.tuhaoSearch,
              creator: this.creatorSearch,
              name: this.nameSearch,
              bianma: this.bianmaSearch,
              syscode: this.syscodeSearch
            }
          }).then(res => {
            if (res.code === "200" && res.data && res.data.length > 0) {
              this.downloadExcel(res.data, '历史码库全部数据');
            } else {
              this.$message.warning('没有找到可导出的数据');
            }
          }).catch(error => {
            console.error('一键导出失败:', error);
            this.$message.error('一键导出失败，请联系管理员');
          }).finally(() => {
            this.pageLoading = false;
          });
        }).catch(() => {});
      },
      
      // 将数据导出为Excel(XLSX)并下载，自动调整单元格宽度
      downloadExcel(data, filename) {
        try {
          // 使用原生方式创建Excel文件，不依赖外部库
          // 1. 准备数据和表头
          const headers = ['ID', '图号', '名称', '规格', '材料', '单重', '类别', 
                          '系统编码', '人工编码', '创建人', '创建时间', '更新人', '更新时间', '备注'];
          const fields = ['id', 'tuhao', 'name', 'guige', 'cailiao', 'danzhong', 'leibie',
                          'syscode', 'bianma', 'creatorName', 'creatTime', 'modifierName', 'updateTime', 'remark'];
          
          // 2. 构建表格内容
          let html = '<table border="1" style="border-collapse: collapse; font-size: 12px;">';
          
          // 添加表头
          html += '<thead><tr style="background-color: #f0f0f0;">';
          headers.forEach(header => {
            html += `<th style="padding: 5px; text-align: left;">${header}</th>`;
          });
          html += '</tr></thead><tbody>';
          
          // 添加数据行
          data.forEach(row => {
            html += '<tr>';
            fields.forEach((field, index) => {
              const value = row[field] || '';
              let cellHtml = '';
              
              // 特殊处理系统编码和人工编码列为文本类型
              // syscode是第7个索引(从0开始)，bianma是第8个索引
              if (field === 'syscode' || field === 'bianma') {
                // 使用mso-number-format样式强制Excel将单元格识别为文本
                // 在值前添加单引号确保Excel不会自动转换格式
                cellHtml = `<td style="padding: 5px; mso-number-format:'\@'">&apos;${String(value)}</td>`;
              } else {
                // 其他列正常处理
                cellHtml = `<td style="padding: 5px;">${String(value)}</td>`;
              }
              
              html += cellHtml;
            });
            html += '</tr>';
          });
          html += '</tbody></table>';
          
          // 3. 添加Excel特定的头部信息
          const excelPrefix = '<html xmlns:o="urn:schemas-microsoft-com:office:office" ' +
                             'xmlns:x="urn:schemas-microsoft-com:office:excel" ' +
                             'xmlns="http://www.w3.org/TR/REC-html40">'
                             + '<head><meta charset="UTF-8"><meta name="ProgId" content="Excel.Sheet">'
                             + '<meta name="Generator" content="Microsoft Excel 15">'
                             + '<style>table {border-collapse:collapse; font-family:Arial,sans-serif;}</style>'
                             + '</head><body>';
          
          const excelSuffix = '</body></html>';
          
          // 4. 组合完整的HTML内容
          const excelContent = excelPrefix + html + excelSuffix;
          
          // 5. 创建Blob对象
          const blob = new Blob([excelContent], { type: 'application/vnd.ms-excel;charset=utf-8;' });
          
          // 6. 生成文件名
          const fullFilename = `${filename}_${this.formatDate(new Date())}.xlsx`;
          
          // 7. 创建下载链接
          const link = document.createElement('a');
          if (link.download !== undefined) { // 支持HTML5下载
            const url = URL.createObjectURL(blob);
            link.setAttribute('href', url);
            link.setAttribute('download', fullFilename);
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            setTimeout(() => URL.revokeObjectURL(url), 100);
          } else {
            // 旧浏览器兼容处理
            this.$message.warning('您的浏览器不支持文件下载，请更新浏览器版本');
          }
          
          this.$message.success('数据导出成功');
        } catch (error) {
          console.error('导出Excel失败:', error);
          this.$message.error('导出Excel失败：' + error.message);
        }
      },
      
      // 格式化日期，用于文件名
      formatDate(date) {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        const hours = String(date.getHours()).padStart(2, '0');
        const minutes = String(date.getMinutes()).padStart(2, '0');
        const seconds = String(date.getSeconds()).padStart(2, '0');
        
        return `${year}${month}${day}${hours}${minutes}${seconds}`;
      }
    }
  }
</script>

<style scoped>
  .input {
    width: 260px;
    margin: 10px;
  }
</style>